package org.blackjuly.sign.data;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.blackjuly.sign.util.JdbcUtil;
import org.blackjuly.sign.util.StringUtil;

public class DataBean<T> {
	
	private Connection conn;
	private String tableName;
	private String primaryKey;
	
	private Class<T> entityClass;
	
	public DataBean(Connection conn, String tableName, String primaryKey) {
		this.conn = conn;
		this.tableName = tableName;
		this.primaryKey = primaryKey;
	}
	
	public void setEntityClass(Class<T> entityClass) {
		this.entityClass = entityClass;
	}
	
	public Class<T> getEntityClass() {
		return this.entityClass;
	}
	
	/**
	 * 新增对象
	 */
	public void doSave(T t) throws Exception {
		Class<?> clazz = t.getClass();
		Field[] fields = clazz.getDeclaredFields();
		List<String> fieldNames = new ArrayList<>();
		for (Field field : fields) {
			if (field.getName().equals(primaryKey)) continue;
			fieldNames.add(field.getName());
		}
		
		StringBuilder sql = new StringBuilder();
		sql.append("insert into ");
		sql.append(tableName);
		sql.append(" (");
		sql.append(StringUtil.join(fieldNames, ", "));
		sql.append(")");
		sql.append(" values(");
		sql.append("?").append(StringUtil.repeat(", ?", fieldNames.size() - 1));
		sql.append(")");
		
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			pstmt = conn.prepareStatement(sql.toString(), Statement.RETURN_GENERATED_KEYS);
			for (int i = 0; i < fieldNames.size(); i++) {
				String fieldName = fieldNames.get(i);
				String methodName = "get" + StringUtil.letter(fieldName);
				Method method = clazz.getDeclaredMethod(methodName);
				pstmt.setObject(i + 1, method.invoke(t));
			}
			pstmt.executeUpdate();
			rs = pstmt.getGeneratedKeys();
			if (rs.next()) {
				Object id = rs.getObject(1);
				String methodName = "set" + StringUtil.letter(primaryKey);
				Method method = clazz.getDeclaredMethod(methodName, id.getClass());
				method.invoke(t, id);
			}
		} catch (Exception e) {
			throw e;
		} finally {
			JdbcUtil.close(pstmt);
			JdbcUtil.close(rs);
		}
	}
	
	/**
	 * 更新对象
	 */
	public void doUpdate(T t) throws Exception {
		Class<?> clazz = t.getClass();
		Field[] fields = clazz.getDeclaredFields();
		List<String> fieldNames = new ArrayList<>();
		for (Field field : fields) {
			if (field.getName().equals(primaryKey)) continue;
			fieldNames.add(field.getName());
		}
		
		StringBuilder sql = new StringBuilder();
		sql.append("update ");
		sql.append(tableName);
		sql.append(" set ");
		
		Iterator<String> iter = fieldNames.iterator();
		if (iter.hasNext())
			sql.append(iter.next()).append(" = ?");
		while (iter.hasNext())
			sql.append(", ").append(iter.next()).append(" = ?");
		
		sql.append(" where ");
		sql.append(primaryKey).append(" = ?");
		System.out.println(sql);
		
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			pstmt = conn.prepareStatement(sql.toString());
			int i;
			for (i = 0; i < fieldNames.size(); i++) {
				String fieldName = fieldNames.get(i);
				String methodName = "get" + StringUtil.letter(fieldName);
				Method method = clazz.getDeclaredMethod(methodName);
				pstmt.setObject(i + 1, method.invoke(t));
			}
			String methodName = "get" + StringUtil.letter(primaryKey);
			Method method = clazz.getDeclaredMethod(methodName);
			pstmt.setObject(i + 1, method.invoke(t));
			
			pstmt.executeUpdate();
		} catch (Exception e) {
			throw e;
		} finally {
			JdbcUtil.close(pstmt);
			JdbcUtil.close(rs);
		}
	}
	
	/**
	 * 删除对象
	 */
	public void doDelete(T t) throws Exception {
		Class<?> clazz = t.getClass();
		
		StringBuilder sql = new StringBuilder();
		sql.append("delte from ");
		sql.append(tableName);
		sql.append(" where ");
		sql.append(primaryKey).append(" = ?");
		
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			pstmt = conn.prepareStatement(sql.toString());
			String methodName = "get" + StringUtil.letter(primaryKey);
			Method method = clazz.getDeclaredMethod(methodName);
			pstmt.setObject(1, method.invoke(t));
			pstmt.executeUpdate();
		} catch (Exception e) {
			throw e;
		} finally {
			JdbcUtil.close(pstmt);
			JdbcUtil.close(rs);
		}
	}
	
	/**
	 * 根据主键查询对象
	 */
	public T doSelect(Object id) throws Exception {
		T entity = null;
		Field[] fields = entityClass.getDeclaredFields();
		List<String> fieldNames = new ArrayList<>();
		for (Field field : fields) {
			fieldNames.add(field.getName());
		}
		
		StringBuilder sql = new StringBuilder();
		sql.append("select * from ").append(tableName).append(" where ").append(primaryKey).append(" = ?");
		
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			entity = entityClass.newInstance();
			pstmt = conn.prepareStatement(sql.toString());
			pstmt.setObject(1, id);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				for (Field field : fields) {
					String methodName = "set" + StringUtil.letter(field.getName());
					Method method = entityClass.getDeclaredMethod(methodName, field.getType());
					method.invoke(entity, rs.getObject(field.getName()));
				}
			}
		} catch (Exception e) {
			throw e;
		}
		
		return entity;
	}
	
}